package com.flame.user.service;

import com.flame.auth.core.constants.AuthConstants;
import com.flame.core.utils.CipherUtils;
import com.flame.core.utils.DateUtils;
import com.flame.parameter.entity.Params;
import com.flame.parameter.service.ParamsService;
import com.flame.user.constants.AccountConstants;
import com.flame.user.controller.vo.AccountPwdVo;
import com.flame.user.controller.vo.AccountVo;
import com.flame.user.entity.Account;
import com.flame.user.entity.UserInfo;
import com.flame.user.exception.UserExceptionMessage;
import com.flame.user.exception.UserRuntimeException;
import com.flame.user.mapper.AccountMapper;
import com.flame.user.mapper.UserInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * flame_user_account 用户账号表
 *
 * @author 吴欣童
 * @since 2022-12-14 16:06:58
 */
@Service
public class AccountService {

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private ParamsService paramsService;

    public List<Account> pageAccount(AccountVo accountVo) {
        return accountMapper.page(accountVo);
    }

    public void addAccount(Account account) {
        Account dbAccount = accountMapper.selectById(account.getAccount());
        if (dbAccount != null) {
            throw new UserRuntimeException(UserExceptionMessage.ACCOUNT_EXIST);
        }
        String password = "123456";
        String defaultPassword = paramsService.getParamsValue("ACCOUNT_DEFAULT_PASSWORD");
        account.setAccountStatus(AccountConstants.ACCOUNT_STATUS_NORMAL);
        if (StringUtils.hasText(defaultPassword)) {
            password = defaultPassword;
        }
        try {
            account.setPassword(CipherUtils.sm3Encrypt(AuthConstants.SALT + password + account.getAccount()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        account.setLoginFailedCount(0);
        accountMapper.insert(account);
    }

    public void updateAccount(Account account) {
        accountMapper.updateById(account);
    }

    public void deleteAccount(Account account) {
        accountMapper.deleteById(account.getAccount());
    }

    public synchronized String generateAccount() {
        String accountSeq = paramsService.getParamsValue("ACCOUNT_SEQ");
        if (StringUtils.hasText(accountSeq)) {
            String account = accountSeq;
            Params params = new Params();
            params.setParamCode("ACCOUNT_SEQ");
            params.setParamValue(String.valueOf(Integer.parseInt(account) + 1));
            paramsService.updateParams(params);
            return account;
        }
        return String.valueOf(System.currentTimeMillis());
    }

    public void freezeAccount(AccountVo accountVo) {
        Account account = new Account();
        account.setAccount(accountVo.getAccount());
        account.setAccountStatus(AccountConstants.ACCOUNT_STATUS_FREEZE);
        accountMapper.updateById(account);
    }

    public void unFreezeAccount(AccountVo accountVo) {
        Account account = new Account();
        account.setAccount(accountVo.getAccount());
        account.setAccountStatus(AccountConstants.ACCOUNT_STATUS_NORMAL);
        accountMapper.updateById(account);
    }

    public void cancelAccount(AccountVo accountVo) {
        Account account = new Account();
        account.setAccount(accountVo.getAccount());
        account.setAccountStatus(AccountConstants.ACCOUNT_STATUS_CANCEL);
        accountMapper.updateById(account);

        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(accountVo.getAccount());
        userInfo.setCancelDate(DateUtils.currentDate());
        userInfoMapper.updateById(userInfo);
    }

    public void resetAccountPwd(AccountVo accountVo) {
        Account account = new Account();
        account.setAccount(accountVo.getAccount());
        String password = "123456";
        String defaultPassword = paramsService.getParamsValue("ACCOUNT_DEFAULT_PASSWORD");
        account.setAccountStatus(AccountConstants.ACCOUNT_STATUS_NORMAL);
        if (StringUtils.hasText(defaultPassword)) {
            password = defaultPassword;
        }
        try {
            account.setPassword(CipherUtils.sm3Encrypt(AuthConstants.SALT + password + account.getAccount()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        accountMapper.updateById(account);
    }

    public void updateAccountPwd(AccountPwdVo accountPwdVo) {
        Account dbAccount = accountMapper.selectById(accountPwdVo.getAccount());
        if (dbAccount == null) {
            throw new UserRuntimeException(UserExceptionMessage.ACCOUNT_NOT_EXIST);
        }
        try {
            // 1、检测旧密码是否相同
            String decryptOldPassword = CipherUtils.sm2Decrypt(accountPwdVo.getOldPassword());
            String encryptOldPassword =
                    CipherUtils.sm3Encrypt(AuthConstants.SALT + decryptOldPassword + accountPwdVo.getAccount());
            if (!dbAccount.getPassword().equals(encryptOldPassword)) {
                throw new UserRuntimeException(UserExceptionMessage.OLD_PASSWORD_NOT_EQUALS);
            }
            // 2、检测密码长度
            String decryptNewPassword = CipherUtils.sm2Decrypt(accountPwdVo.getNewPassword());
            String maxLength = paramsService.getParamsValue("ACCOUNT_PASSWORD_MAX_LENGTH");
            String minLength = paramsService.getParamsValue("ACCOUNT_PASSWORD_MIN_LENGTH");
            if (!StringUtils.hasText(maxLength)) {
                maxLength = "32";
            }
            if (decryptNewPassword.length() > Integer.parseInt(maxLength)) {
                throw new UserRuntimeException(UserExceptionMessage.NEW_PASSWORD_TOO_LONG, maxLength);
            }
            if (!StringUtils.hasText(minLength)) {
                minLength = "6";
            }
            if (decryptNewPassword.length() < Integer.parseInt(minLength)) {
                throw new UserRuntimeException(UserExceptionMessage.NEW_PASSWORD_TOO_SHORT, minLength);
            }
            // 3、检测密码强度
            String passwordStrength = paramsService.getParamsValue("ACCOUNT_PASSWORD_STRENGTH");
            if (!StringUtils.hasText(passwordStrength)) {
                passwordStrength = AccountConstants.PASSWORD_STRENGTH_LOW;
            }
            int count = 0;
            char[] chs = decryptNewPassword.toCharArray();
            for (char item : chs) {
                if (item >= 'a' && item <= 'z') {
                    count++;
                    break;
                }
            }
            for (char value : chs) {
                if (value >= 'A' && value <= 'Z') {
                    count++;
                    break;
                }
            }
            for (char c : chs) {
                if (c >= '0' && c <= '9') {
                    count++;
                    break;
                }
            }
            for (char ch : chs) {
                boolean f1 = !(ch >= 'a' && ch <= 'z');
                boolean f2 = !(ch >= 'A' && ch <= 'Z');
                boolean f3 = !(ch >= '0' && ch <= '9');
                if (f1 && f2 && f3) {
                    count++;
                    break;
                }
            }
            if (AccountConstants.PASSWORD_STRENGTH_HIGH.equals(passwordStrength) && count < 3) {
                throw new UserRuntimeException(UserExceptionMessage.NEW_PASSWORD_STRENGTH_NOT_HIGH);
            }
            if (AccountConstants.PASSWORD_STRENGTH_MIDDLE.equals(passwordStrength) && count < 2) {
                throw new UserRuntimeException(UserExceptionMessage.NEW_PASSWORD_STRENGTH_NOT_MIDDLE);
            }
            if (AccountConstants.PASSWORD_STRENGTH_LOW.equals(passwordStrength) && count < 1) {
                throw new UserRuntimeException(UserExceptionMessage.NEW_PASSWORD_STRENGTH_NOT_LOW);
            }
            // 4、保存新密码
            String encryptNewPassword =
                    CipherUtils.sm3Encrypt(AuthConstants.SALT + decryptNewPassword + accountPwdVo.getAccount());
            Account account = new Account();
            account.setAccount(accountPwdVo.getAccount());
            account.setPassword(encryptNewPassword);
            accountMapper.updateById(account);
        } catch (UserRuntimeException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
